﻿using System.Net;
using System.Reflection;
using System.Text;

using BodaNetCommunications.Cores;
using BodaNetCommunications.Nodes;
using BodaNetCommunications.Utilities.Attributes;
using BodaNetCommunications.Utilities.Results;

namespace BodaNetCommunications.OpcComs
{
    public class OpcUaCommService : CommReadWrite, IOpcUaCommService
    {
        public ConnectionOptions Options { get; private set; }

        public bool IsConnected { get; private set; }


        private readonly IOpcUaService _opcUaService;

        public OpcUaCommService()
        {
            _opcUaService = new OpcUaService();
        }

        public BodaResult Connect(ConnectionOptions connectionOptions)
        {
            BodaResult bodaResult = new BodaResult();

            Options = connectionOptions;

            if (string.IsNullOrEmpty(Options.Ip) || false == IPAddress.TryParse(Options.Ip, out _))
            {
                bodaResult.IsSuccess = false;
                bodaResult.Message = $"Ip[{Options.Ip}]为空或者格式不正确";
                return bodaResult;
            }

            if (Options.Port < 0 || Options.Port > 65535)
            {
                bodaResult.IsSuccess = false;
                bodaResult.Message = $"Port[{Options.Port}]不正确";
                return bodaResult;
            }

            if (IsConnected)
            {
                bodaResult.IsSuccess = true;
                bodaResult.Message = $"OpcUa【{Options.Ip}:{Options.Port}】的连接已经在线，不需要重复连接";
                return bodaResult;
            }

            _byteTransform.EndianType = Utilities.ComTypes.EndianType.ABCD;

            var url = $"opc.tcp://{connectionOptions.Ip}:{connectionOptions.Port}";
            return _opcUaService.AnonymousConnect(url, connectionOptions.OptionName ?? connectionOptions.Ip!, 10000);
        }

        public void Disconnect()
        {
            _opcUaService?.DisConnect();
        }

        public void Dispose()
        {
            Disconnect();
        }

        public BodaResult Write<T>(string address, T value)
        {
            BodaResult bodaResult = new BodaResult();
            if (_opcUaService == null || !_opcUaService.IsConnected)
            {
                bodaResult.IsSuccess = false;
                bodaResult.Message = $"OpcUa session is not connected";
                return bodaResult;
            }

            List<RequestNode> requestNodes = new List<RequestNode>();
            requestNodes.Add(new RequestNode { NodeAddress = address, WriteVarValue = value });

            return _opcUaService.UAWrite(requestNodes, null);
        }

        /// <summary>
        /// 重写基础数据的读取功能
        /// </summary>
        /// <param name="address">数据地址: ns=2;s=Tag.Statistics.PLC.OKString|int</param>
        /// <param name="length">数据个数</param>
        /// <returns></returns>
        public override BodaResult<byte[]> Read(string address, ushort length)
        {
            BodaResult<byte[]> bodaResult = new BodaResult<byte[]>();
            if (_opcUaService == null || !_opcUaService.IsConnected)
            {
                bodaResult.IsSuccess = false;
                bodaResult.Message = $"OpcUa session is not connected";
                return bodaResult;
            }

            List<RequestNode> requestNodes = new List<RequestNode>();
            requestNodes.Add(new RequestNode { NodeAddress = address });
            var res = _opcUaService.UARead(requestNodes, null);
            BodaResult<byte[]>? readResult = new BodaResult<byte[]>();
            if (res.IsSuccess)
            {
                var node = requestNodes.FirstOrDefault();
                if (node == null)
                {
                    bodaResult.IsSuccess = false;
                    bodaResult.Message = $"{address}获取节点失败";
                    return bodaResult;
                }
                if (node.ReadVarValue == null || string.IsNullOrEmpty(node.ReadVarValue.ToString()))
                {
                    bodaResult.IsSuccess = false;
                    bodaResult.Message = $"{address}读取节点数据为空";
                    return bodaResult;
                }

                string val = node.ReadVarValue.ToString()!;
                if (node.ReadVarType == null || string.IsNullOrEmpty(node.ReadVarType?.ToString()))
                {
                    readResult.IsSuccess = false;
                    readResult.Message = $"[{address}]未获取到读取的变量类型";
                    return readResult;
                }

                // 获取数据类型对应的Type
                var dataTyepAttr = node.ReadVarType.GetType()?.
                                        GetField(node.ReadVarType.ToString()!)?.
                                        GetCustomAttribute<PlcDataTypeAttribute>()?.
                                        DataType;
                if (dataTyepAttr == null)
                {
                    readResult.IsSuccess = false;
                    readResult.Message = $"[{address}]未获取到读取的变量类型";
                    return readResult;
                }

                if (dataTyepAttr == typeof(string))
                {
                    readResult.IsSuccess = true;
                    readResult.Content = Encoding.UTF8.GetBytes(val);
                    return readResult;
                }

                // 根据参数类型，获取BitConverter中GetBytes方法
                Type tBitConverter = typeof(BitConverter);
                MethodInfo? method = tBitConverter.GetMethods(BindingFlags.Public | BindingFlags.Static)
                    .FirstOrDefault(mi =>
                            mi.Name.Equals("GetBytes") &&
                            mi.ReturnType == typeof(byte[]) &&
                            mi.GetParameters().Count() == 1 &&
                            mi.GetParameters().FirstOrDefault()!.ParameterType == dataTyepAttr) as MethodInfo;
                if (method == null)
                {
                    readResult.IsSuccess = false;
                    readResult.Message = $"[{address}]未获取到数据转换的方法";
                    return readResult;
                }

                // 根据类型，获取对应Type的Parse方法
                MethodInfo? parseMethod = dataTyepAttr.GetMethod("Parse", new[] { typeof(string) });
                // 调用 Parse 方法，并获取结果
                object? result = parseMethod?.Invoke(null, new object[] { val });
                if (result == null)
                {
                    readResult.IsSuccess = false;
                    readResult.Message = $"[{address}]Parse方法转换失败";
                    return readResult;
                }
                // 将结果转换为目标数据类型
                object convertedValue = Convert.ChangeType(result, dataTyepAttr);

                readResult.Content = method.Invoke(tBitConverter, new object[] { convertedValue }) as byte[];
            }
            else
            {
                readResult.IsSuccess = false;
                readResult.Message = res.Message;
            }
            return readResult;
        }

        public BodaResult<byte> ReceiveMsg(int timeout = 2000, int bytesLen = 1024)
        {
            throw new NotImplementedException();
        }

        public BodaResult SendMsgc(byte[] bytes, int timeout = 1500)
        {
            throw new NotImplementedException();
        }
    }
}
